commonlibsse_ng\re\t/
TESObjectREFR.rs1mod vtable;
2
3pub use self::vtable::TESObjectREFRVtbl;
4
5use core::ffi::c_void;
6use core::ptr::NonNull;
7use std::collections::HashMap;
8
9use crate::re::BSAnimationGraphEvent::BSAnimationGraphEvent;
10use crate::re::BSHandleRefObject::BSHandleRefObject;
11use crate::re::BSTArray::BSTSmallArray;
12use crate::re::BSTEvent::BSTEventSink;
13use crate::re::ExtraContainerChanges::ExtraContainerChanges;
14use crate::re::ExtraDataList::ExtraDataList;
15use crate::re::IAnimationGraphManagerHolder::IAnimationGraphManagerHolder;
16use crate::re::InventoryChanges::InventoryChanges;
17use crate::re::InventoryEntryData::InventoryEntryData;
18use crate::re::NiAVObject::NiAVObject;
19use crate::re::NiPoint3::NiPoint3;
20use crate::re::NiSmartPointer::NiPointer;
21use crate::re::TESBoundObject::TESBoundObject;
22use crate::re::TESForm::TESForm;
23use crate::re::TESObjectCELL::TESObjectCELL;
24use crate::re::{ObjectHandle, TesWaterForm};
25
26#[repr(C)]
29#[derive(Debug)]
30pub struct OBJ_REFR {
31 pub objectReference: *mut TESBoundObject, pub angle: NiPoint3, pub location: NiPoint3, }
35
36const _: () = assert!(core::mem::size_of::<OBJ_REFR>() == 0x20);
37
38#[derive(Debug)]
39#[repr(C)]
40pub struct LOADED_REF_DATA {
41 pub unk00: BSTSmallArray<*mut c_void>, pub current_water_type: *mut TesWaterForm,
43 pub relevant_water_height: f32,
44 pub cached_radius: f32,
45 pub flags: u16,
46 pub underwater_count: i16,
47 pub unk30: u64,
48 pub unk38: u64,
49 pub unk40: u64,
50 pub unk48: u64,
51 pub unk50: u64,
52 pub unk58: u64,
53 pub unk60: u64,
54 pub data_3d: NiPointer<NiAVObject>,
55 pub unk70: *mut c_void, }
57
58#[repr(C)]
59#[derive(Debug)]
60pub struct TESObjectREFR {
61 pub __base: TESForm, pub __base1: BSHandleRefObject, pub __base2: BSTEventSink<BSAnimationGraphEvent>, pub __base3: IAnimationGraphManagerHolder, pub data: OBJ_REFR, pub parentCell: *mut TESObjectCELL, pub loadedData: *mut LOADED_REF_DATA, pub extraList: ExtraDataList, }
70const _: () = assert!(core::mem::size_of::<TESObjectREFR>() == 0x78);
71
72impl crate::re::NiSmartPointer::RefCountable for TESObjectREFR {
73 #[inline]
74 fn inc_ref_count(&self) {
75 self.__base1.inc_ref_count();
76 }
77
78 #[inline]
79 fn dec_ref_count(&mut self) {
80 self.__base1.dec_ref_count();
81 }
82}
83
84type Count = i32;
85pub type InventoryCountMap = HashMap<*mut TESBoundObject, Count>;
86pub type InventoryItemMap = HashMap<*mut TESBoundObject, (Count, Box<InventoryEntryData>)>;
87pub type InventoryDropMap = HashMap<*mut TESBoundObject, (Count, Vec<ObjectHandle>)>;
88
89impl TESObjectREFR {
90 pub fn get_inventory_filter<F>(&self, filter: F, no_init: bool) -> Option<InventoryItemMap>
91 where
92 F: Fn(&TESBoundObject) -> bool,
93 {
94 let inventory_changed = self.get_inventory_changes(no_init)?;
95 let inventory_changed = unsafe { &*inventory_changed };
96
97 let mut inventory = InventoryItemMap::new();
98 for entry in unsafe { inventory_changed.entryList.as_ref()?.iter() } {
99 if entry.is_null() {
100 continue;
101 }
102
103 let entry_ref = unsafe { entry.as_ref()? };
104 let object = entry_ref.object;
105 if filter(unsafe { object.as_ref()? }) {
106 inventory.insert(object, (entry_ref.countDelta, Box::new(entry_ref.clone())));
107 }
108 }
109
110 Some(inventory)
111 }
112
113 pub fn get_inventory_changes(&self, no_init: bool) -> Option<*mut InventoryChanges> {
118 if !self.extraList.has_type(ExtraContainerChanges::EXTRA_DATA_TYPE) {
119 if no_init {
120 return None;
121 };
122
123 if !self.init_inventory_if_required(false) {
124 self.force_init_inventory_changes();
125 }
126 }
127 let x_container = self.extraList.get_by_type_as::<ExtraContainerChanges>()?;
128 Some(unsafe { x_container.as_ref() }.changes)
129 }
130
131 #[inline]
132 pub const fn get_object_reference(&self) -> *mut TESBoundObject {
133 self.data.objectReference
134 }
135
136 #[commonlibsse_ng_derive_internal::relocate_fn(se_id = 15800, ae_id = 16038)]
139 pub fn init_inventory_if_required(&self, ignore_container_extra_data: bool) -> bool {}
140
141 pub fn force_init_inventory_changes(&self) -> *mut InventoryChanges {
142 let changes = self.make_inventory_changes();
143 if !changes.is_null() {
144 let changes = unsafe { &*changes };
145 changes.init_leveled_items();
146 changes.init_from_container_extra();
147 changes.init_scripts();
148 }
149 changes
150 }
151
152 pub fn make_inventory_changes(&self) -> *mut InventoryChanges {
155 type SelfSignature = fn(this: *const ()) -> *mut InventoryChanges;
156
157 {
158 static FUNC: std::sync::LazyLock<SelfSignature> = std::sync::LazyLock::new(|| {
159 use crate::rel::ResolvableAddress as _;
160 use crate::rel::id::RelocationID;
161
162 const SE_ID: u64 = 15802;
163 const AE_ID: u64 = 16040;
164
165 let fn_ptr =
166 RelocationID::new(SE_ID, AE_ID, SE_ID).address().unwrap_or_else(|err| {
167 #[cfg(feature = "tracing")]
168 tracing::error!("[Critical Error] Failed to resolve address: {err}");
169 panic!("Failed to resolve address: {err}")
170 });
171 unsafe { core::mem::transmute::<NonNull<c_void>, SelfSignature>(fn_ptr) }
172 });
173 FUNC((self as *const Self).cast())
174 }
175 }
176}